package com.qumitech.visualnovel.service.gameData.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.qumitech.visualnovel.component.exception.BusinessException;
import com.qumitech.visualnovel.component.util.CommonUtil;
import com.qumitech.visualnovel.component.util.DateUtil;
import com.qumitech.visualnovel.component.util.HttpInvokeUtil;
import com.qumitech.visualnovel.model.common.BaseRsp;
import com.qumitech.visualnovel.model.common.ResultEnum;
import com.qumitech.visualnovel.model.common.BaseResponse;
import com.qumitech.visualnovel.controller.vo.gameData.*;
import com.qumitech.visualnovel.datasource.console.PlayGameResultMapper;
import com.qumitech.visualnovel.datasource.console.DataQueryConfDOMapper;
import com.qumitech.visualnovel.datasource.console.DataQueryRecordDOMapper;
import com.qumitech.visualnovel.datasource.console.DataQueryPermissionDOMapper;
import com.qumitech.visualnovel.datasource.console.DataQueryRolePermissionDOMapper;
import com.qumitech.visualnovel.model.dao.console.UserInfo;
import com.qumitech.visualnovel.model.dao.console.SysRole;
import com.qumitech.visualnovel.model.dao.console.RemainUserCount;
import com.qumitech.visualnovel.model.dao.console.DataQueryConfDO;
import com.qumitech.visualnovel.model.dao.console.DataQueryRecordDO;
import com.qumitech.visualnovel.model.dao.console.DataQueryPermissionDO;
import com.qumitech.visualnovel.model.dao.console.DataQueryRolePermissionDO;
import com.qumitech.visualnovel.model.common.UrlConstant;
import com.qumitech.visualnovel.service.gameData.GameDataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.SecurityUtils;

import java.util.*;

@Service
public class GameDataServiceImpl implements GameDataService {

    @Autowired
    PlayGameResultMapper playGameResultMapper;

    @Autowired
    DataQueryConfDOMapper dataQueryConfDOMapper;

    @Autowired
    DataQueryRecordDOMapper dataQueryRecordDOMapper;

    @Autowired
    DataQueryPermissionDOMapper dataQueryPermissionDOMapper;

    @Autowired
    DataQueryRolePermissionDOMapper dataQueryRolePermissionDOMapper;

    @Autowired
    DateUtil dateUtil;


    @Override
    public GameDataDTO getPlayGameData(GameDataQueryDTO gameDataQueryDTO) {

        String[] stringTime = CommonUtil.setStartTime(gameDataQueryDTO.getStartTime(), gameDataQueryDTO.getEndTime());
        List<String> tableList = CommonUtil.getTableListFromDate(stringTime[0], stringTime[1], "play_game_result");
        gameDataQueryDTO.setTableList(tableList);
        GameDataDTO gameDataDTO = new GameDataDTO();
        HashMap<String, Object> enterGameStatistic = playGameResultMapper.enterGameStatisticInfo(gameDataQueryDTO);

        gameDataDTO.setEnterGameAccountNumber(Integer.valueOf(enterGameStatistic.get("enter_game_account_number").toString()));
        gameDataDTO.setEnterGameTimes(Integer.valueOf(enterGameStatistic.get("enter_game_times").toString()));

        HashMap<String, Object> startGameStatisticInfo = playGameResultMapper.startGameStatisticInfo(gameDataQueryDTO);
        gameDataDTO.setOpenGameAccountNumber(Integer.valueOf(startGameStatisticInfo.get("open_game_account_number").toString()));
        gameDataDTO.setOpenGameTimes(Integer.valueOf(startGameStatisticInfo.get("open_game_times").toString()));

        gameDataDTO.setCount(playGameResultMapper.getCount(gameDataQueryDTO));
        gameDataDTO.setPlayGameResultDTOList(playGameResultMapper.getList(gameDataQueryDTO));
        return gameDataDTO;
    }

    private JSONObject getSeriesItem(String matchTypeName, Map<String,Double> tempMap)
    {
        JSONObject seriesItem = new JSONObject();
        seriesItem.put("name", matchTypeName);
        seriesItem.put("type", "line");
        JSONArray seriesItemDataList = new JSONArray();
        for(String key : tempMap.keySet()) {
            seriesItemDataList.add(tempMap.get(key));
        }
        seriesItem.put("data", seriesItemDataList);
        JSONObject areaStyle = JSONObject.parseObject("{normal: {}}");
        seriesItem.put("areaStyle", areaStyle);
        return seriesItem;
    }

    @Override
    public JSONObject getOpenGameTimesLine(String startTime, String endTime, Long accountId, String[] gameIds) {
        JSONObject gameIdMap = getGames();
        String[] stringTime = CommonUtil.setStartTime(startTime, endTime);
        List<String> tableList = CommonUtil.getTableListFromDate(stringTime[0], stringTime[1], "play_game_result");
        List<PlayGameStatisticsDTO> allGameTimesStatistics = playGameResultMapper.getAllGameTimesLine(startTime, endTime, accountId,tableList);
        JSONObject res_all = getLines(startTime, endTime, allGameTimesStatistics);
        if (allGameTimesStatistics.size() == 0) {
            return res_all;
        }
        if (gameIds != null) {
            allGameTimesStatistics = playGameResultMapper.getGameTimesLine(startTime, endTime, accountId, gameIds, tableList);
            JSONObject res = getLines(startTime, endTime, allGameTimesStatistics, gameIdMap);
            res.getJSONObject("legend").getJSONArray("data").add(res_all.getJSONObject("legend").getJSONArray("data").get(0));
            res.getJSONArray("series").add(res_all.getJSONArray("series").get(0));
            return res;
        } else {
            return res_all;
        }
    }

    @Override
    public JSONObject getOpenGameNumbersLine(String startTime, String endTime, String[] gameIds) {
        JSONObject gameIdMap = getGames();
        String[] stringTime = CommonUtil.setStartTime(startTime, endTime);
        List<String> tableList = CommonUtil.getTableListFromDate(stringTime[0], stringTime[1], "play_game_result");
        List<PlayGameStatisticsDTO> allGameTimesStatistics = playGameResultMapper.getAllGameNumbersLine(startTime, endTime,tableList);
        JSONObject res_all = getLines(startTime, endTime, allGameTimesStatistics);
        if (allGameTimesStatistics.size() == 0) {
            return res_all;
        }
        if (gameIds != null) {
            allGameTimesStatistics = playGameResultMapper.getGameNumbersLine(startTime, endTime, gameIds, tableList);
            JSONObject res = getLines(startTime, endTime, allGameTimesStatistics, gameIdMap);
            res.getJSONObject("legend").getJSONArray("data").add(res_all.getJSONObject("legend").getJSONArray("data").get(0));
            res.getJSONArray("series").add(res_all.getJSONArray("series").get(0));
            return res;
        } else {
            return res_all;
        }
    }

    @Override
    public JSONObject getGameAverageTimesLine(String startTime, String endTime, String[] gameIds) {
        JSONObject gameIdMap = getGames();
        String[] stringTime = CommonUtil.setStartTime(startTime, endTime);
        List<String> tableList = CommonUtil.getTableListFromDate(stringTime[0], stringTime[1], "play_game_result");
        List<PlayGameStatisticsDTO> allGameTimesStatistics = playGameResultMapper.getAllGameAverageTimesLine(startTime, endTime,tableList);
        JSONObject res_all = getLines(startTime, endTime, allGameTimesStatistics);
        if (allGameTimesStatistics.size() == 0) {
            return res_all;
        }
        if (gameIds != null) {
            allGameTimesStatistics = playGameResultMapper.getGameAverageTimesLine(startTime, endTime, gameIds, tableList);
            JSONObject res = getLines(startTime, endTime, allGameTimesStatistics, gameIdMap);
            res.getJSONObject("legend").getJSONArray("data").add(res_all.getJSONObject("legend").getJSONArray("data").get(0));
            res.getJSONArray("series").add(res_all.getJSONArray("series").get(0));
            return res;
        } else {
            return res_all;
        }
    }

    @Override
    public JSONObject getStatisticList(String startTime, String endTime, Long accountId, String[] gameIds, Integer offset, Integer limit) {
        JSONObject data = new JSONObject();
        String[] stringTime = CommonUtil.setStartTime(startTime, endTime);
        List<String> tableList = CommonUtil.getTableListFromDate(stringTime[0], stringTime[1], "play_game_result");
        data.put("count", playGameResultMapper.getStatisticCount(startTime, endTime, accountId, gameIds, tableList));
        List<PlayGameStatisticsListDTO> playGameStatisticsListDTOS = playGameResultMapper.getStatisticList(startTime, endTime,accountId,gameIds, tableList, offset, limit);
        data.put("items", playGameStatisticsListDTOS);
        return data;
    }

    public JSONObject getGames() {
        String GAME_BASE_INFO_URL = "/game/baseinfo";
        String url = UrlConstant.SERVER_URL + GAME_BASE_INFO_URL;
        Map<String, String> paramMap = new HashMap<>();
        String body = HttpInvokeUtil.httpGet(url, paramMap, null);
        BaseRsp rsp = JSONObject.parseObject(body, BaseRsp.class);
        if (rsp == null || rsp.getStatus() != ResultEnum.SUCCESS.getState()
                || rsp.getData() == null) {
            throw new BusinessException(ResultEnum.FAILURE);
        }
        Map<String, Object> rspMap = (Map<String, Object>) rsp.getData();
        JSONArray gameList = (JSONArray)rspMap.get("game_base_info");
        JSONObject gameIdMap = new JSONObject();
        for(int i=0; i<gameList.size(); i++){
            JSONObject item = gameList.getJSONObject(i);
            gameIdMap.put(item.getString("game_id"), item.getString("game_name"));
        }
        return gameIdMap;
    }

    private JSONObject getLines(String startTime, String endTime, List <PlayGameStatisticsDTO> playGameStatisticsDTOList) {
        JSONObject legend = new JSONObject();
        JSONArray legendList = new JSONArray();
        legend.put("data",legendList);

        JSONArray xAxis = new JSONArray();
        List<String> dateList= dateUtil.getnDayList(startTime, endTime);
        JSONObject xAxisData = new JSONObject();
        xAxisData.put("data", JSONArray.parseArray(JSON.toJSONString(dateList)));
        xAxis.add(xAxisData);

        JSONArray series = new JSONArray();
        boolean isFirst = true;
        String lastType = null;
        Map<String,Double>  tempMap = null;
        for (PlayGameStatisticsDTO playGameStatisticsDTO: playGameStatisticsDTOList)
        {
            if(isFirst)
            {
                tempMap = dateUtil.GetNDaysDoubleMap(startTime,endTime);
                lastType = playGameStatisticsDTO.getGameId();
                isFirst = false;
            }
            if (!lastType.equals(playGameStatisticsDTO.getGameId()))
            {
                legendList.add(lastType);
                series.add(getSeriesItem(lastType, tempMap));
                lastType = playGameStatisticsDTO.getGameId();
                tempMap = dateUtil.GetNDaysDoubleMap(startTime,endTime);
            }
            tempMap.put(dateUtil.dateToStr(playGameStatisticsDTO.getTargetDate()),playGameStatisticsDTO.getData());
        }
        if(lastType !=null)
        {
            legendList.add(lastType);
            series.add(getSeriesItem(lastType, tempMap));
        }
        JSONObject resObj = new JSONObject();
        resObj.put("legend", legend);
        resObj.put("xAxis", xAxis);
        resObj.put("series", series);
        return resObj;
    }

    private JSONObject getLines(String startTime, String endTime, List <PlayGameStatisticsDTO> playGameStatisticsDTOList, JSONObject matchTypeMap) {
        JSONObject legend = new JSONObject();
        JSONArray legendList = new JSONArray();
        legend.put("data",legendList);
        JSONArray xAxis = new JSONArray();
        List<String> dateList= dateUtil.getnDayList(startTime, endTime);
        JSONObject xAxisData = new JSONObject();
        xAxisData.put("data", JSONArray.parseArray(JSON.toJSONString(dateList)));
        xAxis.add(xAxisData);
        xAxis.add(JSONObject.parse("{\"type\": \"category\"}"));
        JSONArray series = new JSONArray();
        boolean isFirst = true;
        String lastType = null;
        Map<String,Double>  tempMap = null;
        for (PlayGameStatisticsDTO playGameStatisticsDTO: playGameStatisticsDTOList)
        {
            if(isFirst)
            {
                tempMap = dateUtil.GetNDaysDoubleMap(startTime,endTime);
                lastType = playGameStatisticsDTO.getGameId();
                isFirst = false;
            }
            if (!lastType.equals(playGameStatisticsDTO.getGameId()))
            {
                String matchTypeName = matchTypeMap.getOrDefault(lastType,lastType).toString();
                legendList.add(matchTypeName);
                series.add(getSeriesItem(matchTypeName, tempMap));
                lastType = playGameStatisticsDTO.getGameId();
                tempMap = dateUtil.GetNDaysDoubleMap(startTime,endTime);
            }
            tempMap.put(dateUtil.dateToStr(playGameStatisticsDTO.getTargetDate()),playGameStatisticsDTO.getData());
        }
        if(lastType != null)
        {
            String matchTypeName = matchTypeMap.getOrDefault(lastType,lastType).toString();
            legendList.add(matchTypeName);
            series.add(getSeriesItem(matchTypeName, tempMap));
        }
        JSONObject resObj = new JSONObject();
        resObj.put("legend", legend);
        resObj.put("xAxis", xAxis);
        resObj.put("series", series);
        return resObj;
    }

    private String getSysUserName() {
        Subject subject = SecurityUtils.getSubject();
        UserInfo activeUser = (UserInfo) subject.getPrincipal();
        return activeUser!=null ? activeUser.getUsername() : "";
    }

    private List<Integer> getSysRoles() {
        Subject subject = SecurityUtils.getSubject();
        UserInfo activeUser = (UserInfo) subject.getPrincipal();
        if (activeUser == null) {
            return null;
        } else {
            List<Integer> list = new ArrayList();
            for (SysRole sysRole : activeUser.getSysRoleList()) {
                list.add(sysRole.getId());
            }
            return list;
        }
    }

    @Override
    public JSONObject getDataQueryConfList(String id, String sysUserName, String startTime,
        String endTime, Integer offset, Integer limit) {
        int count = dataQueryConfDOMapper.getCount(id, sysUserName, startTime, endTime);
        List<DataQueryConfDO> items = dataQueryConfDOMapper.getList(id, sysUserName, startTime, endTime, offset, limit);
        JSONObject result = new JSONObject();
        result.put("count", count);
        result.put("items", items);
        return result;
    }

    @Override
    public void modDataQueryConf(Long id, GameDataQueryConfDTO conf) {
        DataQueryConfDO item = new DataQueryConfDO();
        item.setId(id);
        item.setSysUserName(getSysUserName());
        item.setDataType(conf.getDataType());
        item.setDataName(conf.getDataName());
        item.setDataComments(conf.getDataComments());
        item.setArgNames(conf.getArgNames());
        dataQueryConfDOMapper.updateByPrimaryKeySelective(item);
    }

    @Override
    public void addDataQueryConfList(GameDataQueryConfDTO conf) {
        DataQueryConfDO item = new DataQueryConfDO();
        item.setSysUserName(getSysUserName());
        item.setDataType(conf.getDataType());
        item.setDataName(conf.getDataName());
        item.setDataComments(conf.getDataComments());
        item.setArgNames(conf.getArgNames());
        dataQueryConfDOMapper.insertSelective(item);
    }

    @Override
    public void delDataQueryConf(Long id) {
        dataQueryConfDOMapper.deleteByPrimaryKey(id);
    }

    @Override
    public JSONObject getDataQueryRecordList(String dataName, String argComments, String sysUserName,
        String startTime, String endTime, Integer offset, Integer limit) {
        sysUserName = sysUserName!=null ? sysUserName : getSysUserName();
        int count = dataQueryRecordDOMapper.getCount(dataName, argComments, sysUserName, startTime, endTime);
        List<DataQueryRecordDO> items = dataQueryRecordDOMapper.getList(dataName, argComments, sysUserName, startTime, endTime, offset, limit);
        JSONObject result = new JSONObject();
        result.put("count", count);
        result.put("items", items);
        return result;
    }

    @Override
    public void addDataQueryRecordList(GameDataQueryRecordDTO record) {
        DataQueryRecordDO item = new DataQueryRecordDO();
        item.setDataConfId(record.getDataConfId());
        item.setSysUserName(getSysUserName());
        item.setArgValues(record.getArgValues());
        item.setArgComments(record.getArgComments());
        dataQueryRecordDOMapper.insertSelective(item);
    }

    @Override
    public JSONArray getDataQueryOptionsDataNames() {
        List<DataQueryConfDO> names = dataQueryConfDOMapper.getDataNames(getSysRoles());
        JSONArray result = new JSONArray();
        for (DataQueryConfDO name : names) {
            JSONObject item = new JSONObject();
            item.put("id", name.getId());
            item.put("text", name.getDataName());
            result.add(item);
        }
        return result;
    }

    @Override
    public JSONArray getDataQueryOptionsDataTypeNames(String dataType) {
        List<DataQueryConfDO> names = dataQueryConfDOMapper.getDataTypeNames(dataType);
        JSONArray result = new JSONArray();
        for (DataQueryConfDO name : names) {
            JSONObject item = new JSONObject();
            item.put("id", name.getId());
            item.put("text", name.getDataName());
            result.add(item);
        }
        return result;
    }

    @Override
    public JSONObject getDataQueryPermissionList() {
        JSONArray level1List = getChildren(0);
        for (int idx=0; idx<level1List.size(); ++idx) {
            JSONObject level1Item = level1List.getJSONObject(idx);
            JSONArray level2List = getChildren(level1Item.getInteger("id"));
            if (level2List.size() > 0) {
                level1Item.put("children", level2List);
            }
            for (int jdx=0; jdx<level2List.size(); ++jdx) {
                JSONObject level2Item = level2List.getJSONObject(jdx);
                JSONArray level3List = getChildren(level2Item.getInteger("id"));
                if (level3List.size() > 0) {
                    level2Item.put("children", level3List);
                }
                for (int kdx=0; kdx<level3List.size(); ++kdx) {
                    JSONObject level3Item = level3List.getJSONObject(kdx);
                    JSONArray level4List = getChildren(level3Item.getInteger("id"));
                    if (level4List.size() > 0) {
                        level3Item.put("children", level4List);
                    }
                }
            }
        }
        JSONObject result = new JSONObject();
        result.put("items", level1List);
        return result;
    }

    private JSONArray getChildren(Integer parentId) {
        JSONArray children = new JSONArray();
        List<DataQueryPermissionDO> items = dataQueryPermissionDOMapper.getList(parentId);
        for (DataQueryPermissionDO item : items) {
            JSONObject jsonItem = new JSONObject();
            jsonItem.put("id", item.getId());
            jsonItem.put("label", item.getName());
            children.add(jsonItem);
        }
        return children;
    }

    @Override
    public JSONObject getDataQueryRolePermission(Integer roleId, String type) {
        JSONObject result = new JSONObject();
        result.put("type", type);
        if (type.equals("permission")) {
            result.put("data", new JSONArray());
            List<DataQueryPermissionDO> list = dataQueryPermissionDOMapper.getPermissions(roleId, null);
            for (DataQueryPermissionDO item : list) {
                if ((item.getLevel()==3) || (item.getLevel()==2 && getChildren(item.getId()).size()==0)) {
                    result.getJSONArray("data").add(item.getId());
                }
            }
        } else if (type.equals("rebateType") || type.equals("walletType")) {
            result.put("data", new JSONArray());
            String name = type.equals("rebateType") ? "合约厅类型" : "收益类型";
            List<DataQueryPermissionDO> list = dataQueryPermissionDOMapper.getPermissions(roleId, name);
            for (DataQueryPermissionDO item : list) {
                JSONObject jsonItem = new JSONObject();
                jsonItem.put("id", item.getNameId());
                jsonItem.put("text", item.getName());
                result.getJSONArray("data").add(jsonItem);
            }
        } else if (type.equals("channelType")) {
            result.put("data", new JSONObject());
            List<DataQueryPermissionDO> mainChannelList = dataQueryPermissionDOMapper.getPermissions(roleId, "渠道类型");
            for (DataQueryPermissionDO mainItem : mainChannelList) {
                String mainChannel = mainItem.getName();
                if (!result.getJSONObject("data").containsKey(mainChannel)) {
                    result.getJSONObject("data").put(mainChannel, new JSONArray());
                }
                List<DataQueryPermissionDO> subChannelList = dataQueryPermissionDOMapper.getPermissions(roleId, mainChannel);
                for (DataQueryPermissionDO subItem : subChannelList) {
                    String subChannel = subItem.getName();
                    result.getJSONObject("data").getJSONArray(mainChannel).add(subChannel);
                }
            }
        }
        return result;
    }

    @Override
    public void addDataQueryRolePermission(JSONObject permission) {
        Integer roleId = permission.getInteger("roleId");
        String permissionIdListStr = permission.getJSONArray("permissionIdList").toJSONString();
        List<Integer> permissionIdList = JSONArray.parseArray(permissionIdListStr, Integer.class);
        dataQueryRolePermissionDOMapper.delPermissions(roleId);
        dataQueryRolePermissionDOMapper.addPermissions(roleId, permissionIdList);
    }
}
